/**
 * ┏┓　　　┏┓
 * ┏┛┻━━━┛┻┓
 * ┃　　　　　　　┃
 * ┃　　　━　　　┃
 * ┃　┳┛　┗┳　┃
 * ┃　　　　　　　┃
 * ┃　　　┻　　　┃
 * ┃　　　　　　　┃
 * ┗━┓　　　┏━┛
 * 　　┃　　　┃神兽保佑
 * 　　┃　　　┃代码无BUG！
 * 　　┃　　　┗━━━┓
 * 　　┃　　　　　　　┣┓
 * 　    ┃　　　　　　　┏┛
 * 　　┗┓┓┏━┳┓┏┛
 * 　　　┃┫┫　┃┫┫
 * 　　　┗┻┛　┗┻┛
 **/
package com.asd.common.listener.reflex;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

import javax.servlet.annotation.WebServlet;

import com.asd.common.annotation.Expose;
import com.asd.common.annotation.OperationBind;
import com.asd.common.utils.Prop;
import com.asd.common.utils.PropKit;

/**
 * @author zhanqi
 * @date 2020-03-07
 */
public class BaseReflex {
    public static Prop p;
    static void loadConfig() {
        if (p == null) {
            p = PropKit.use("config.properties").appendIfExists("config-pro.properties");
        }
    }
    // 扫描接口
    protected Map<String, List<Map<String, Object>>> list() {
        loadConfig();
        Map<String, List<Map<String, Object>>> map = new HashMap<>();
        String webserviceReflexAnnotationType = p.get("webserviceReflexAnnotationType");
        if (null == webserviceReflexAnnotationType) {
            return map;
        }
        Map<String, Class<?>> beanMap = BeanReflexMemory.of().getAllBean();
        String[] webserviceReflexAnnotationTypes = webserviceReflexAnnotationType.split(",");
        for (int i = 0; i < webserviceReflexAnnotationTypes.length; i++) {
            String annotationType = webserviceReflexAnnotationTypes[i];
            List<Map<String, Object>> list = new ArrayList<>();
            for (String key : beanMap.keySet()) {
                Class<?> targetClass = beanMap.get(key);
                Map<String, Object> record = new HashMap<>();

                WebServlet controllerBind = targetClass.getAnnotation(WebServlet.class);
                if (controllerBind == null) {
                    continue;
                }
                String routesValue = controllerBind.name();
                // 获取方法上@ControllerBind注解的value值
                String path = controllerBind.urlPatterns()[0];
                record.put("lable", routesValue);
                // 获取方法上的注解
                List<Map<String, Object>> dataList = getMethodsList(targetClass, controllerBind, path, webserviceReflexAnnotationTypes[i]);
                if (dataList.size() > 0 && dataList != null) {
                    record.put("data", dataList);
                    list.add(record);
                }
            }
            map.put(annotationType, list);
        }


        return map;
    }

    // 获取方法上的注解
    private List<Map<String, Object>> getMethodsList(Class<?> clazz, WebServlet controllerBind, String path, String annotationType) {
        List<Map<String, Object>> dataList = new ArrayList<>();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            Annotation[] annotations = method.getDeclaredAnnotations();
            for (Annotation annotation : annotations) {
                if (annotation.annotationType().getSimpleName().equals(annotationType)) {
                    String operationBindValue = null;
                    switch (annotationType) {
                        case "OperationBind":
                            OperationBind c = method.getAnnotation(OperationBind.class);
                            if (c != null) {
                                operationBindValue = c.value();
                            }
                            break;
                        case "Expose":
                            Expose b = method.getAnnotation(Expose.class);
                            if (b != null) {
                                operationBindValue = b.value();
                            }
                            break;
                    }
                    if (controllerBind != null && operationBindValue != null) {
                        Map<String, Object> data = new HashMap<>();
                        data.put("value", path + "/" + method.getName());
                        data.put("name", operationBindValue);
                        dataList.add(data);

                    }
                }

            }
        }
        return dataList;
    }
}
